Pablo Garcia

Apps for iPhone, iPad, Apple TV and Apple Watch

Fun with enums (Fun with flags)

Sep 23, 2018

Fun with Enums - API Endpoint

Swift enums are pretty awesome. For a person like me, whose first programming language was C (a long, long, long time ago), it's like a breath of fresh air.

Enums are first-class types and can adopt features traditionally supported only by classes:

  • Conform to protocols
  • Computed properties
  • Instance methods
  • Initializers

Basic Enums

Let's start with a classic example

enum Guitar {
  case classical
  case electric
  case acoustic
 }

Associated values

Associated values are a perfect way to add additional information to enums. Imagine for instance that you would like to add some information to our enum example. A guitar has a serial number. An electric guitar could have one, two or more pickups, an acoustic guitar could be electrified or not and so on. Let's translate this into code.

enum Guitar {
    case classical(serialNumber: String)
    case electric(serialNumber: String, pickups: Int)
    case acoustic(serialNumber: String, electrified: Bool)
}

let classicalGuitar = Guitar.classical(serialNumber: "SW87234")
let electricGuitar = Guitar.electric(serialNumber: "HG0983", pickups: 2)
let acousticGuitar = Guitar.acoustic(serialNumber: "JJ8888", electrified: false)

if case let Guitar.acoustic(serialNumber, electrified) = acousticGuitar {

    print("Acoustic guitar. Serial number\(serialNumber). Electrified: \(electrified)")
}

Output:

  Acoustic guitar. Serial numberJJ8888. Electrified: false

Enums and protocols

For example, we could model API Endpoints with enums. What we would like to do is build different endpoints based on our needs. Take the TFL Unified API for instance. To retrieve lines status for a few lines (victoria, piccadilly and central), we'd have to build something like this https://api.tfl.gov.uk//Line/victoria,piccadilly,central/Status

Wouldn't it be great if, with a simple line of code, we could get this url? That's pretty cool but you will say...Ooh great!....show me the code!!! Ok, let's do it.

We define a protocol with a url variable

protocol EndPointProtocol {
    var url: URL { get }
}
enum LineEndPoint {
    case validmodes
    case lineStatus([String])
}
extension LineEndPoint: EndPointProtocol {

    var url: URL {

        guard var url = URLComponents(string: "https://api.tfl.gov.uk") else { fatalError("Error") }

        switch self {
        case .validmodes:
            url.path = "/Line/Meta/Modes"
        case .lineStatus(let idLines):
            let linesIdcommaseparated = getCommaSeparated(array: idLines)
            url.path = "/Line/\(linesIdcommaseparated)/Status"
        }

        let urlFinal = url.url

        return urlFinal!
    }

    private func getCommaSeparated(array: [String]) -> String {
        return array.map { String($0)}.joined(separator: ",")
    }
}

The only thing we have to do is:



let lineStatus = LineEndPoint.lineStatus(["victoria","piccadilly","central"])

print("Line status endpoint: \(lineStatus.url)")

Output:

Line status endpoint: https://api.tfl.gov.uk/Line/victoria,piccadilly,central/Status

And that's it. A fancy and elegant way of getting endpoints.